<?php
declare(strict_types=1);

namespace app\service;

use app\model\{Order, Kuaidi100Order};
use think\facade\{Log, Cache};
use GuzzleHttp\Client;
use Exception;

class Kuaidi100Service extends BaseService
{
    protected $config;
    protected $client;
    
    public function __construct()
    {
        $this->config = [
            'key' => env('KUAIDI100.KEY'),
            'customer' => env('KUAIDI100.CUSTOMER'),
            'secret' => env('KUAIDI100.SECRET'),
            'siid' => env('KUAIDI100.SIID'),
            'tid' => env('KUAIDI100.TID'),
            'secret_key' => env('KUAIDI100.SECRET_KEY'),
            'callback_url' => env('KUAIDI100.CALLBACK_URL'),
        ];
        
        $this->client = new Client([
            'base_uri' => 'https://poll.kuaidi100.com',
            'timeout' => 5.0,
        ]);
    }

    /**
     * 创建快递100订单
     */
    public function createOrder(Order $order): bool
    {
        try {
            $config = $this->getConfig();
            
            // 构建请求参数
            $params = [
                'kuaidicom' => $order->company_code,
                'sendMan' => [
                    'name' => $order->sender_name,
                    'mobile' => $order->sender_phone,
                    'province' => $order->sender_province,
                    'city' => $order->sender_city,
                    'district' => $order->sender_county,
                    'address' => $order->sender_address
                ],
                'recMan' => [
                    'name' => $order->receiver_name,
                    'mobile' => $order->receiver_phone,
                    'province' => $order->receiver_province,
                    'city' => $order->receiver_city,
                    'district' => $order->receiver_county,
                    'address' => $order->receiver_address
                ],
                'cargo' => '快递包裹',
                'weight' => $order->weight_estimate,
                'serviceType' => $order->business_type,
                'dayType' => 1, // 工作日
                'orderType' => 2, // 预约取件
                'pickupStartTime' => $order->pickup_date . ' ' . $order->pickup_start_time, // 预约取件开始时间
                'pickupEndTime' => $order->pickup_date . ' ' . $order->pickup_end_time,     // 预约取件结束时间
                'salt' => uniqid(),
                'callbackUrl' => $this->getCallbackUrl($order->merchant_id)
            ];

            // 如果有保价
            if ($order->insure_amount > 0) {
                $params['valinsPay'] = $order->insure_amount;
            }

            // 签名
            $params['sign'] = $this->generateSign($params, $config['key']);

            // 发送请求
            $response = $this->sendRequest('/api/order', $params);
            
            if ($response['status'] != 200) {
                throw new Exception($response['message'] ?? '下单失败');
            }

            // 保存快递100订单信息
            $order->save([
                'kuaidi100_order_id' => $response['data']['taskId'],
                'courier_name' => $response['data']['courier_name'] ?? '',
                'courier_phone' => $response['data']['courier_phone'] ?? ''
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('快递100下单失败: ' . $e->getMessage());
            throw new Exception('快递100下单失败: ' . $e->getMessage());
        }
    }

    /**
     * 取消快递100订单
     */
    public function cancelOrder(string $orderId): bool
    {
        try {
            $params = [
                'key' => $this->config['key'],
                'parameters' => json_encode([
                    'orderId' => $orderId,
                    'cancelMsg' => '用户取消订单'
                ])
            ];

            // 签名
            $params['sign'] = strtoupper(md5($params['parameters'] . $this->config['key'] . $this->config['secret']));

            // 发送请求
            $response = $this->client->post('/order/cancel', [
                'form_params' => $params
            ]);

            $result = json_decode($response->getBody()->getContents(), true);
            if (!$result || $result['status'] != 200) {
                throw new \Exception($result['message'] ?? '取消订单失败');
            }

            // 更新快递100订单状态
            Kuaidi100Order::where('order_id', $orderId)->update([
                'status' => 99 // 已取消
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('快递100取消订单失败: ' . $e->getMessage());
            throw new \Exception('快递100取消订单失败: ' . $e->getMessage());
        }
    }

    /**
     * 处理快递100回调
     */
    public function handleCallback(array $data): bool
    {
        try {
            // 验证签名
            if (!$this->verifySign($data)) {
                throw new Exception('签名验证失败');
            }

            // 更新订单状态
            $order = Order::where('kuaidi100_order_id', $data['taskId'])->find();
            if (!$order) {
                throw new Exception('订单不存在');
            }

            // 更新订单状态和快递员信息
            $status = $this->mapOrderStatus($data['status']);
            $order->save([
                'order_status' => $status,
                'courier_name' => $data['courierName'] ?? '',
                'courier_phone' => $data['courierPhone'] ?? '',
                'express_no' => $data['expressNo'] ?? ''
            ]);

            // 如果是已取件状态，记录实际取件时间
            if ($status == 10) {
                $order->save([
                    'pickup_actual_time' => date('Y-m-d H:i:s')
                ]);
            }

            return true;

        } catch (\Exception $e) {
            Log::error('处理快递100回调失败: ' . $e->getMessage());
            throw new Exception('处理快递100回调失败: ' . $e->getMessage());
        }
    }

    /**
     * 查询快递价格
     */
    public function queryPrice(
        string $serviceCode,
        string $fromProvince,
        string $fromCity,
        string $toProvince,
        string $toCity,
        float $weight
    ): array {
        try {
            // 查询价格逻辑...
            return [
                'total_price' => 0, // 实现实际的价格查询逻辑
            ];
        } catch (\Exception $e) {
            Log::error('查询快递价格失败: ' . $e->getMessage());
            throw new \Exception('查询快递价格失败: ' . $e->getMessage());
        }
    }

    /**
     * 获取配置
     */
    protected function getConfig(): array
    {
        return [
            'key' => env('KUAIDI100.KEY'),
            'customer' => env('KUAIDI100.CUSTOMER'),
            'secret' => env('KUAIDI100.SECRET'),
            'callback_url' => env('KUAIDI100.CALLBACK_URL')
        ];
    }

    /**
     * 生成签名
     */
    protected function generateSign(array $params, string $key): string
    {
        // 按键名升序排序
        ksort($params);
        
        // 拼接参数
        $str = '';
        foreach ($params as $k => $v) {
            if ($k != 'sign' && !is_array($v)) {
                $str .= $k . '=' . $v . '&';
            }
        }
        $str = rtrim($str, '&');
        
        // 加密
        return strtoupper(md5($str . $key));
    }

    /**
     * 发送请求
     */
    protected function sendRequest(string $uri, array $params): array
    {
        $response = $this->client->post($uri, [
            'form_params' => $params
        ]);
        
        return json_decode($response->getBody()->getContents(), true);
    }

    /**
     * 获取回调地址
     */
    protected function getCallbackUrl(int $merchantId): string
    {
        return str_replace('{merchant_id}', $merchantId, $this->config['callback_url']);
    }

    /**
     * 验证签名
     */
    protected function verifySign(array $data): bool
    {
        $sign = $data['sign'] ?? '';
        unset($data['sign']);
        
        return $sign === $this->generateSign($data, $this->getConfig()['key']);
    }

    /**
     * 映射订单状态
     */
    protected function mapOrderStatus(int $status): int
    {
        $statusMap = [
            1 => 1,   // 已接单
            2 => 2,   // 收件中
            10 => 10, // 已取件
            11 => 11, // 揽收失败
            13 => 13, // 已签收
            14 => 14  // 异常签收
        ];
        
        return $statusMap[$status] ?? $status;
    }
} 